package cn.iocoder.yudao.module.vos.service.tenantrequestlog;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.vos.controller.admin.tenantrequestlog.vo.TenantRequestLogPageReqVO;
import cn.iocoder.yudao.module.vos.controller.admin.tenantrequestlog.vo.TenantRequestLogSaveReqVO;
import cn.iocoder.yudao.module.vos.controller.admin.tenantrequestlog.vo.TenantRequestMonthlyBillRow;
import cn.iocoder.yudao.module.vos.dal.dataobject.tenantrequestlog.TenantRequestLogDO;
import cn.iocoder.yudao.module.vos.dal.mysql.tenantrequestlog.TenantRequestLogMapper;
import cn.iocoder.yudao.module.vos.service.tenantrequestlog.vo.TenantRequestMonthlyBillAggDO;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Validated
public class TenantRequestLogServiceImpl implements TenantRequestLogService {

    @Resource
    private TenantRequestLogMapper tenantRequestLogMapper;

    private static final String TABLE_PREFIX = "submeter_tenant_request_log_";
    private static final DateTimeFormatter MONTH_FMT = DateTimeFormatter.ofPattern("yyyyMM");

    /** 生成分表表名：固定前缀 + yyyyMM */
    private String tableNameByMonth(LocalDateTime ts) {
        LocalDateTime t = (ts != null) ? ts : LocalDateTime.now();
        return TABLE_PREFIX + t.format(MONTH_FMT);
    }

    /** 从查询时间区间里挑一个“定位月份”的时间点；没给就用现在 */
    private String resolveTableNameForQuery(TenantRequestLogPageReqVO reqVO) {
        LocalDateTime pick = null;
        if (reqVO != null && reqVO.getCreateTime() != null && reqVO.getCreateTime().length >= 1) {
            pick = reqVO.getCreateTime()[0]; // 以起始时间所在月为准
        }
        String table = tableNameByMonth(pick);
        return table;
    }

    /** 插入时根据实体的 createTime 决定分表；若为空则用 now，并自动建表 */
    private String resolveTableNameForInsert(TenantRequestLogDO entity) {
        LocalDateTime ts = entity != null ? entity.getCreateTime() : null;
        if (ts == null) {
            ts = LocalDateTime.now();
            if (entity != null) {
                entity.setCreateTime(ts);
            }
        }
        String table = tableNameByMonth(ts);
        ensureMonthlyTable(table);
        return table;
    }

    /** 自动建表（幂等）：CREATE TABLE IF NOT EXISTS ${table} LIKE submeter_tenant_request_log */
    private void ensureMonthlyTable(String tableName) {
        // 只接受我们生成的安全表名，避免注入
        if (tableName == null || !tableName.matches("^" + TABLE_PREFIX + "\\d{6}$")) {
            throw new IllegalArgumentException("illegal table name: " + tableName);
        }
        tenantRequestLogMapper.createTableIfNotExists(tableName);
    }

    // ============ 分表后的能力：仅保留 create / page（导出依赖 page 的无分页） ============

    @Override
    public Long createTenantRequestLog(TenantRequestLogSaveReqVO createReqVO) {
        TenantRequestLogDO entity = BeanUtils.toBean(createReqVO, TenantRequestLogDO.class);
        // BaseDO 字段兜底
        if (entity.getCreateTime() == null) {
            entity.setCreateTime(LocalDateTime.now());
        }
        if (entity.getUpdateTime() == null) {
            entity.setUpdateTime(entity.getCreateTime());
        }
        if (entity.getDeleted() == null) {
            entity.setDeleted(false);
        }
        final String table = resolveTableNameForInsert(entity);
        tenantRequestLogMapper.insertByTable(table, entity);
        // 自增主键在分表内递增；此处无法回填 id（简单实现），如需回填可改为 SELECT LAST_INSERT_ID()
        return entity.getId();
    }

    @Override
    public Long createTenantRequestLog(TenantRequestLogDO createReqVO) {
        // BaseDO 字段兜底
        if (createReqVO.getCreateTime() == null) {
            createReqVO.setCreateTime(LocalDateTime.now());
        }
        if (createReqVO.getUpdateTime() == null) {
            createReqVO.setUpdateTime(createReqVO.getCreateTime());
        }
        if (createReqVO.getDeleted() == null) {
            createReqVO.setDeleted(false);
        }
        final String table = resolveTableNameForInsert(createReqVO);
        tenantRequestLogMapper.insertByTable(table, createReqVO);
        return createReqVO.getId();
    }


    @Override
    public PageResult<TenantRequestLogDO> getTenantRequestLogPage(TenantRequestLogPageReqVO pageReqVO) {
        final String table = resolveTableNameForQuery(pageReqVO);

        // 是否“导出全部”
        boolean noPage = pageReqVO.getPageSize() != null
                && pageReqVO.getPageSize().intValue() == PageParam.PAGE_SIZE_NONE;

        if (noPage) {
            List<TenantRequestLogDO> all = tenantRequestLogMapper.selectListByTableNoPage(table, pageReqVO);
            return new PageResult<>(all, (long) all.size());
        }

        int pageNo = pageReqVO.getPageNo() == null ? 1 : Math.max(1, pageReqVO.getPageNo());
        int pageSize = pageReqVO.getPageSize() == null ? 10 : Math.max(1, pageReqVO.getPageSize());
        int offset = (pageNo - 1) * pageSize;

        List<TenantRequestLogDO> list = tenantRequestLogMapper.selectPageByTable(table, pageReqVO, offset, pageSize);
        long total = tenantRequestLogMapper.selectCountByTable(table, pageReqVO);
        return new PageResult<>(list, total);
    }

    // ============ 以下接口在分表模式下不再支持（你说暂时没用到，直接抛异常更安全） ============

    @Override
    public void updateTenantRequestLog(TenantRequestLogSaveReqVO updateReqVO) {
        throw new UnsupportedOperationException("Sharding mode does not support generic update. 请按月表定向更新或关闭该接口。");
    }

    @Override
    public void deleteTenantRequestLog(Long id) {
        throw new UnsupportedOperationException("Sharding mode does not support generic delete by id. 请按月表定向删除或关闭该接口。");
    }

    @Override
    public void deleteTenantRequestLogListByIds(List<Long> ids) {
        throw new UnsupportedOperationException("Sharding mode does not support generic batch delete. 请按月表定向删除或关闭该接口。");
    }

    @Override
    public TenantRequestLogDO getTenantRequestLog(Long id) {
        throw new UnsupportedOperationException("Sharding mode does not support generic get by id（不同月表 id 可能重复）.");
    }

    /** 根据 YearMonth 定位分表（yyyyMM） */
    private String tableNameByYearMonth(YearMonth ym) {
        return TABLE_PREFIX + ym.format(MONTH_FMT);
    }



    @Override
    public List<TenantRequestMonthlyBillRow> exportMonthlyBill(String yearMonth) {
        if (yearMonth == null || !yearMonth.matches("^\\d{4}-\\d{2}$")) {
            throw new IllegalArgumentException("yearMonth 格式应为 yyyy-MM，例如 2025-10");
        }
        YearMonth ym = YearMonth.parse(yearMonth);
        String table = tableNameByYearMonth(ym);
        if (tenantRequestLogMapper.existsTable(table) == 0) {
            return Collections.emptyList();
        }
        List<TenantRequestMonthlyBillAggDO> aggs = tenantRequestLogMapper.selectMonthlyBillByTable(table);
        return aggs.stream().map(a -> {
            TenantRequestMonthlyBillRow r = new TenantRequestMonthlyBillRow();
            r.setYearMonth(a.getYm());
            // requestTypeLabel 字段使用 DictConvert 渲染中文，但值需传入 code
            r.setRequestTypeLabel(a.getRequestType());
            r.setRequestType(a.getRequestType());
            r.setSecretId(a.getSecretId());
            r.setTimes(a.getTimes());
            r.setUnitPrice(a.getUnitPrice());
            r.setTotalAmount(a.getTotalAmount());
            return r;
        }).collect(Collectors.toList());
    }
}
